home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Precision Software Appli…tions Silver Collection 1
/
Precision Software Applications Silver Collection Volume One (PSM) (1993).iso
/
windows
/
games
/
xlmath21.arj
/
SOURCE.ZIP
/
XLUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-10
|
26KB
|
1,011 lines
/*******************************************************************
XLUTIL.C
==========
Author & Copyright:
Roy Kari
Dept. of Chemistry
Laurentian University
Sudbury, Ont.
Canada P3E 2C6
(705) 675-1151
Internet: "ROY@NICKEL.LAURENTIAN.CA"
This module contains all of the memory management routines for
Standalone DLL's. Optionally, the memory management is done with the aid
of the SMARTHEAP memory manager (c) Applegate Software (206)868-8512.
This module also contains pascal string routines and Excel reference
manipulation rotuines.
***************************************************************** */
/* --------------------------< Include files >--------------------- */
#define WIN31
#define _MSC_VER 700
#include <windows.h>
#include <xlcall.h>
#include <stdlib.h>
#include <framewrk.h>
/*----------------------------------------------------------------------*\
You can use both XLAUTO and XLUTIL as general purpose modules
to be included in all of your XLL's. A few modifications are required
but these are easily handles by logical conditionals such as those
shown below.
\*----------------------------------------------------------------------*/
#ifdef _XLMATH
#include <xlmath.h>
#endif
#ifdef _XLMARK
#include <xlmark.h>
#endif
#ifdef _XLQC
#include <.\xlqc\xlqc.h>
#endif
#include "xlutil.h"
/*----------------------------------------------------------------------*\
Memory Utilities
When I began this project, "real" mode windows was still a reality.
This meant that memory use was a "real" problem. The only way to
get by the problem was to use a memory allocator such as SMARTHEAP.
Today, with Windows 3.1 and finally Microsoft C/C++ 7, one can
go back to the "old fashioned way" of allocating memory - using
the large model compiler and malloc() and free(). SMARTHEAP still
provides memory debugging techniques superior to standard C but not
superior to C++.
My problem is that I wrote this mess with "real" mode in mind and
compiled it with casts to near and far pointers. I can easily
change to use old fashioned memory allocations but I cannot easily
change to the large model. Hence, what follows is a hybrid. In your
own usage, I suggest thast you forget about near and far data pointers
and let the comiler sort it out.
\*----------------------------------------------------------------------*/
/********************************************************************
GetMem()
=============
This function allocates memory for temporary storage
********************************************************************/
LPVOID PASCAL GetMem(WORD wBytes)
{
LPVOID lpPtr;
lpPtr = (LPVOID)MemAllocPtr(gScratchPool, wBytes, TRUE);
if (lpPtr == NULL)
ErrorHandler(XLU_NO_MEMORY);
return (lpPtr);
}
/********************************************************************
FreeMem()
=============
This function de-allocates memory previously allocated in GetMem()
********************************************************************/
void PASCAL FreeMem(LPVOID lpPtr)
{
if ((MemFreePtr((LPVOID)lpPtr) == FALSE))
ErrorHandler(XLU_MEMORY_ERROR);
lpPtr = NULL;
}
/* -------------------< MALLOC SUBSTITUTE >--------------------- */
#ifndef _USE_SMARTHEAP
/*
** Basically, the routines below are dummy routines with the **
** exception of the memory allocation routines which simply **
** allocate memory in the far heap. If you use standard C **
** then you can change the calls to the Microsoft far **
** heap allocators _fmalloc() to the standard malloc() etc. I **
** didn't because I wanted to retain the ability to use the medium **
** model with far data pointers. **
*/
LPVOID PASCAL MemAllocPtr(MEM_POOL pool, WORD wSize,
BOOL bZeroInit)
{
if (bZeroInit)
return (LPVOID)_fcalloc((size_t) wSize, sizeof(char));
else
return (LPVOID)_fmalloc((size_t)wSize);
}
LPVOID PASCAL MemReAllocPtr(LPVOID lpMem, WORD wSize,
BOOL bZeroInit)
{
size_t sizeOld, sizeNew;
LPVOID lpNew;
if (bZeroInit)
{
sizeOld = _fmsize(lpMem);
lpNew = (LPVOID)_frealloc(lpMem, (size_t)wSize);
sizeNew = _fmsize(lpNew);
if ( sizeNew > sizeOld )
{
_fmemset((LPVOID)((LPSTR)lpNew+sizeOld), 0,
(size_t)(sizeNew-sizeOld) );
return lpNew;
}
}
else
return (LPVOID)_frealloc(lpMem, (size_t)wSize);
}
BOOL PASCAL MemFreePtr(LPVOID lpPtr)
{
_ffree(lpPtr);
return TRUE;
}
//
// The following are SMARTHEAP specific routines which here
// are duplicated as dummy routines.
//
MEM_POOL PASCAL MemPoolInit(BOOL bShared)
{
return ((MEM_POOL)NULL);
}
BOOL PASCAL MemPoolFree(MEM_POOL pool)
{
_fheapmin();
return TRUE;
}
DWORD PASCAL MemPoolCount(MEM_POOL pool)
{
return (DWORD)0;
}
BOOL PASCAL MemCheckPtr(MEM_POOL pool, LPVOID lpPtr)
{
// Can't do much here except check to see that the ptr is
// a ptr to a valid XLOPER of type multi
return TRUE; // do nothing
}
BOOL PASCAL MemSetSafetyLevel(int Dum1, BOOL bFlag)
{
return bFlag;
}
#endif // USE_SMARTHEAP
/*----------------------------------------------------------------------*\
Array Utilities
All data is passed back to Excel in an XLOPER of type
xltypeMulti. When using custom functions, this data memory
is released when Excel calls back xlAutoFree(). When using
dialog boxes, the memory is released in the dialog box routine.
It is more convenient to define a xlMulti data structure
whose memory can be deallocated with a single pointer. The
function InitMulti() allocates and initializes this xlMulti
array.
\*----------------------------------------------------------------------*/
/********************************************************************
InitMulti()
=============
This function allocates the XL MULTI array in global memory &
inits the array.
********************************************************************/
LPMULTI PASCAL InitMulti(WORD wRows, WORD wCols, WORD xlType)
{
WORD wSizeData = sizeof(XLOPER)*wRows*wCols;
WORD i;
LPMULTI lpMulti = NULL;
// the array is allocated in one shot which means
// that it can be freed with one pointer. There is no
// need to free the array memory separately
lpMulti = (LPMULTI)MemAllocPtr(gReturnPool,
sizeof(XLOPER)*(wRows*wCols+1), FALSE);
if (lpMulti)
{
// init Multi to call back to xlAutoFree()
lpMulti->Info.xltype = (xltypeMulti | xlbitDLLFree);
// set the array pointer
lpMulti->Info.val.array.lparray = (LPXLOPER)&lpMulti->Data[0];
// set the rows
lpMulti->Info.val.array.rows = wRows;
// set the columns
lpMulti->Info.val.array.columns = wCols;
for (i = 0; i < wRows*wCols; i++)
{
// each XLOPER is initialized to type xlType and zeroed
// note that the memory will be freed with lpMulti.
lpMulti->Data[i].xltype = xlType;
lpMulti->Data[i].val.num = 0.0;
}
}
else
{
ErrorHandler(XLU_NO_MEMORY);
return NULL;
}
return (lpMulti);
}
//
// InitNum() - Init an XLOPER of type Num
//
LPXLOPER PASCAL InitNum(VOID)
{
LPXLOPER lpxlNum = (LPXLOPER)MemAllocPtr(gReturnPool,
sizeof(XLOPER), TRUE);
if (lpxlNum)
{
lpxlNum->xltype = xltypeNum | xlbitDLLFree;
lpxlNum->val.num = 0;
}
else
{
ErrorHandler(XLU_NO_MEMORY);
return NULL;
}
return (lpxlNum);
}
LPXLOPER StripxlbitDLLFree(LPXLOPER lpX)
{
lpX->xltype = lpX->xltype ^ xlbitDLLFree;
return (lpX);
}
/********************************************************************
InitPointers()
=============
This function allocates memory and calculates the pointers for a 2-D
array.
********************************************************************/
LPLPREAL PASCAL InitPointers(LPREAL lpData,
WORD wRows, WORD wCols)
{
WORD id;
LPLPREAL lplpPtrs;
WORD wBytes = sizeof(LPREAL)*wRows;
if ((lplpPtrs= (LPLPREAL)GetMem(wBytes)) == NULL)
{
ErrorHandler(XLU_NO_MEMORY);
return NULL;
}
// init row pointers
for(id = 0; id < wRows; id++)
{
lplpPtrs[id] = lpData;
lpData += wCols;
}
return(lplpPtrs);
}
/* ---------------------------------------------------------------------
Utility allocate and free space for dynamic 2D arrays
--------------------------------------------------------------------- */
LPLPVOID AllocateArray2D(int NumberOfRows, int NumberOfColumns,
size_t SizeOfElement, size_t SizeOfPointers)
{
register int i;
LPSTR lpArray;
LPLPSTR lplpRow;
size_t SizeOfRow;
/* allocate memory for data */
lpArray = (LPSTR)GetMem(NumberOfRows*NumberOfColumns*SizeOfElement);
if (lpArray == NULL)
{
return NULL;
}
/* allocate memory for row pointers */
lplpRow = (LPLPSTR)GetMem(NumberOfRows * SizeOfPointers);
if( lplpRow == NULL)
{
FreeMem( lpArray);
return NULL;
}
/* initialize row pointers */
SizeOfRow = SizeOfElement * NumberOfColumns;
for(i = 0; i < NumberOfRows; i++)
{
lplpRow[i] = lpArray;
lpArray += SizeOfRow;
}
return (LPLPVOID)lplpRow;
}
void FreeArray2D(LPLPVOID lplpRow)
{
FreeMem((LPVOID)*lplpRow); /* free the data space */
FreeMem((LPVOID)lplpRow); /* free the row pointers */
}
/*----------------------------------------------------------------------*\
Error Handling Utilities
\*----------------------------------------------------------------------*/
/********************************************************************
ErrorHandler()
================
This function is used to display an error message
********************************************************************/
BOOL PASCAL ErrorHandler(XLM_ERROR nErrorCode)
{
if (LoadString(ghLibInst, nErrorCode, gszErrorBuf, MAX_ERROR_STRING) > 0)
{
gszErrorBuf[0] = (BYTE)lstrlen((LPSTR)gszErrorBuf);
Excel(xlcAlert, 0, 3, (LPXLOPER)TempStr((LPSTR)gszErrorBuf),
(LPXLOPER)TempNum(3), (LPXLOPER)gpxHelpRef);
}
return TRUE;
}
/****************************************************************************
FUNCTION: OkMsgBox(PSTR, PSTR, ...)
PURPOSE: Put a Formatted MessageBox
****************************************************************************/
void cdecl OkMsgBox(LPSTR lpFormat, ...)
{
static char rgch[256];
wvsprintf(rgch, lpFormat, (LPSTR)((&lpFormat)+1));
rgch[0] = (BYTE)lstrlen((LPSTR)rgch);
Excel(xlcAlert, 0, 3, (LPXLOPER)TempStr((LPSTR)rgch),
(LPXLOPER)TempNum(2), (LPXLOPER)gpxHelpRef);
}
#ifdef DEBUG
//
// debugPrinto() - debugPrintf an xloper; Incomplete
//
int PASCAL debugPrinto(LPXLOPER px)
{
static char rgch[256];
LPXLMREF pxl;
WORD xltype = px->xltype & 0x0FFF;
debugPrintf(" xltype=%x",px->xltype);
switch (xltype)
{
case xltypeStr:
MakePstr((LPSTR)rgch,(LPSTR)px->val.str);
debugPrintf(" Str=%s",(LPSTR)rgch);
break;
case xltypeSRef:
debugPrintf(" count=%d \nrwF=%d rwL=%d colF=%d colL=%d",
px->val.sref.count, px->val.sref.ref.rwFirst,
px->val.sref.ref.rwLast, px->val.sref.ref.colFirst,
px->val.sref.ref.colLast);
break;
case xltypeRef:
pxl = px->val.mref.lpmref;
debugPrintf(" count=%d \nrwF=%d rwL=%d colF=%d colL=%d",
pxl->count,
pxl->reftbl[0].rwFirst, pxl->reftbl[0].rwLast,
pxl->reftbl[0].colFirst, pxl->reftbl[0].colLast);
break;
case xltypeMulti:
debugPrintf(" xltypeMulti\nrows=%d cols=%d\n lparray=%x : %x",
px->val.array.rows, px->val.array.columns,
HIWORD(px->val.array.lparray), LOWORD(px->val.array.lparray));
break;
default:
break;
}
return 1;
}
#endif
/*----------------------------------------------------------------------*\
Pascal String Utilities
Excel works with Pascal type strings which have a byte count
as the first byte in the string. This leads to several complications
which can be more easily resolved with the following utility functions.
\*----------------------------------------------------------------------*/
//
// InitPascalStrings()
// Byte count the strings & add count to string
//
VOID InitPascalStrings (LPSTR *lpStr, UINT nRows, UINT nCols)
{
UINT i, j, ij;
ij=0;
for (i=0; i<nRows; i++)
{
for (j=0; j<nCols; j++)
{
lpStr[ij+j][0] = (BYTE) lstrlen(lpStr[ij+j]+1);
}
ij += nCols;
}
}
//
// MakePstr() - copy a C string to a Pascal type
// return no. char copied
//
int PASCAL MakePstr(LPSTR lpPstr, LPSTR lpCstr)
{
BYTE i;
lpPstr[0] = (BYTE)lstrlen(lpCstr);
for (i=0; i<(BYTE)lpPstr[0]; i++)
lpPstr[i+1] = lpCstr[i];
return ((int)(BYTE)(lpPstr[0]));
}
//
// pstrcpy() copy a Pascal type string to a C type string
// return no. char copied
//
int PASCAL MakeCstr(LPSTR lpCstr, LPSTR lpPstr)
{
BYTE i;
lpCstr[0]='\0';
if ( (BYTE)lpPstr[0]<256 )
{
for (i = 0; i < (BYTE)lpPstr[0]; i++)
lpCstr[i]=lpPstr[i+1];
lpCstr[i]='\0';
}
return (int)((BYTE)lpPstr[0]);
}
//
// lstrcatszpz(lpszstr1, lpsppstr2 ) concatenates sp string to
// sz string leaving sz string
//
LPSTR PASCAL lstrcatszsp(LPSTR lpszStr, LPSTR lpspStr)
{
BYTE to, from, nchar;
to = (BYTE)lstrlen((LPSTR)lpszStr);
from = 1;
nchar = (BYTE)lpspStr[0];
while (nchar > 0)
{
lpszStr[to++] = lpspStr[from++];
--nchar;
}
lpszStr[to] = '\0';
return (LPSTR) lpszStr;
}
/*
** lpstricmp
**
** Compare two pascal strings and check if they are equal,
** without sensitivity to case.
**
** Parameters:
**
** LPSTR s First string
** LPSTR t Second string
**
** Returns:
**
** int 0 if they are equal
** Nonzero otherwise
**
** Note:
**
** Unlike the usual string functions, lpstricmp
** doesn't care about collating sequence.
*/
int PASCAL lpstricmp(LPSTR s, LPSTR t)
{
int i;
if (*s != *t)
{
return 1;
}
for (i=1; i<=s[0]; i++)
{
if (tolower(s[i]) != tolower(t[i]))
{
return 1;
}
}
return 0;
}
#if 0
// This just duplicates the Excel Find() function. It
// isn't required but I just don't have the heart to delete
// it!
void Find(LPXLOPER pxPos, LPXLOPER pxFindT, LPXLOPER pxFindIn)
{
BYTE i, j;
BOOL bSuccess = FALSE;
for (i=1; i<=(BYTE)pxFindIn->val.str[0]; i++)
{
if (pxFindT->val.str[1] == pxFindIn->val.str[i])
{
bSuccess = TRUE;
if ((BYTE)pxFindT->val.str[0] > 1)
{
for (j=0; j<(BYTE)pxFindT->val.str[0]; j++)
{
if (pxFindT->val.str[j+1] != pxFindIn->val.str[i+j])
{
bSuccess = FALSE;
break;
}
}
}
break;
}
}
if (bSuccess)
{
pxPos->xltype = xltypeNum;
pxPos->val.num = i;
}
else
{
pxPos->xltype = xltypeErr;
pxPos->val.err = 15;
}
}
#endif
/*----------------------------------------------------------------------*\
Reference Utilities
The following group of routines will help you to retrieve
and create Excel ranges. This requires several helper routines
but with these rotuines, it is quite simple to retrieve ranges
from dialog boxes and create ranges to use with the xlSet command.
For usage, see the routines in XLMDLG.C
\*----------------------------------------------------------------------*/
//////////////////////////////////////////////////////////////
//
// InitDialog()
//
/////////////////////////////////////////////////////////////
BOOL InitDialog(LPXLOPER lpxDialog, LPSTR *rgDlg, UINT nRows)
{
LPXLOPER px;
UINT i, j, ij;
px = lpxDialog->val.array.lparray = (LPXLOPER)GetMem(
(sizeof(XLOPER)*7*nRows));
if (px == NULL)
return FALSE;
// fill in the array
ij=0;
for (i=0; i<nRows; i++)
{
for (j=0; j<7; j++)
{
if (rgDlg[ij+j][0] == (BYTE)0)
{
px->xltype = xltypeNil;
}
else
{
px->xltype = xltypeStr;
px->val.str = rgDlg[ij+j];
}
px++;
}
ij += 7;
}
lpxDialog->xltype = xltypeMulti;
lpxDialog->val.array.rows = nRows;
lpxDialog->val.array.columns = 7;
return TRUE;
}
//
// GetSheetId() - gets sheet name and sheetid for active sheet
// returns TRUE if found, else FALSE
//
BOOL GetActiveSheetId(void)
{
BYTE i = 1;
if (xlretSuccess != Excel(xlSheetId, &gxActiveSheetId, 0))
{
// error; no active sheet
ErrorHandler(XLU_NO_ACTIVESHEET);
return FALSE;
}
// get active sheet's name
Excel(xlfGetWindow, &gxActiveSheetName, 1, TempInt(1));
if (gxActiveSheetName.xltype == xltypeStr)
{
// save name in C string & get SheetId
MakeCstr((LPSTR)gszActiveSheetName, (LPSTR)gxActiveSheetName.val.str);
Excel(xlSheetId, (LPXLOPER)&gxActiveSheetId, 1,
(LPXLOPER)&gxActiveSheetName);
return TRUE;
}
// only in case of error
return FALSE;
}
//
// TrimPrefix() - strip the sheet name from a text reference
// if the text reference refers to the active sheet. Else
// does not strip sheetname
//
void PASCAL TrimPrefix(LPXLOPER pxRefText)
{
BYTE i,j, len;
XLOPER xTemp;
XLOPER xSheetName1, xActiveSheetName;
// get active sheet's name
Excel(xlfGetWindow, &xActiveSheetName, 1, TempInt(1));
// extract sheet name from input ref
Excel(xlfFind, &xTemp, 2, (LPXLOPER)TempStr((LPSTR)" !"), (LPXLOPER)pxRefText);
// Find(&xTemp, TempStr((LPSTR)" !"), pxRefText);
if (xTemp.xltype != xltypeErr)
{
--xTemp.val.num;
Excel(xlfLeft, &xSheetName1, 2, (LPXLOPER)pxRefText,
(LPXLOPER)&xTemp);
if (lpstricmp(xActiveSheetName.val.str, xSheetName1.val.str)==0)
{
// active and ref sheet names are the same
// strip sheet name from reference
j = (BYTE)xTemp.val.num + 1;
len = (BYTE)pxRefText->val.str[0] - j;
for (i=1; i<=len; i++)
{
pxRefText->val.str[i] = pxRefText->val.str[i+j];
}
pxRefText->val.str[0] = len;
}
}
Excel(xlFree, 0, 1, (LPXLOPER)&xSheetName1);
Excel(xlFree, 0, 1, (LPXLOPER)&xActiveSheetName);
}
/////////////////////////////////////////////////////////////////////////////
//
// GetRefTextFromSelection() - Initialize the dialog box reference edit
// controls for both input and output. The input range is defined from
// the selection and the output range is defined as to the right or below
//
///////////////////////////////////////////////////////////////////////////
int PASCAL GetRefTextFromSelection(LPXLOPER pxRefTextIn,
LPXLOPER pxRefTextOut, BYTE Offset)
{
XLOPER xSel, xOutRef;
// get selection in text form
Excel(xlfSelection, (LPXLOPER)&xSel, 0);
if (xSel.xltype != xltypeSRef)
{
ErrorHandler(XLU_BAD_REF);
return FALSE;
}
// create output reference
xOutRef.xltype=xltypeSRef;
xOutRef.val.sref.count=1;
if ((xSel.val.sref.ref.rwLast - xSel.val.sref.ref.rwFirst) >
(WORD)(xSel.val.sref.ref.colLast- xSel.val.sref.ref.colFirst) )
{
// rows > cols so to right
xOutRef.val.sref.ref.rwFirst = xOutRef.val.sref.ref.rwLast =
xSel.val.sref.ref.rwFirst;
xOutRef.val.sref.ref.colFirst = xOutRef.val.sref.ref.colLast =
xSel.val.sref.ref.colLast+(WORD)Offset;
}
else
{
// rows < cols so below
xOutRef.val.sref.ref.rwFirst = xOutRef.val.sref.ref.rwLast =
xSel.val.sref.ref.rwLast + Offset;
xOutRef.val.sref.ref.colFirst = xOutRef.val.sref.ref.colLast =
xSel.val.sref.ref.colFirst;
}
// convert to string form: this returns a string so must
// be freed later
Excel(xlfReftext, pxRefTextIn, 2, (LPXLOPER)&xSel, TempBool(TRUE));
Excel(xlfReftext, pxRefTextOut,2, (LPXLOPER)&xOutRef, TempBool(TRUE));
// strip the sheet ID from the reference
TrimPrefix(pxRefTextIn);
TrimPrefix(pxRefTextOut);
// free the selection string
Excel(xlFree, 0, 1, (LPXLOPER)&xSel);
return 1;
}
//
// SetInitalRange() - Sets the dialog box default from selected cell or range
//
int PASCAL SetInitialRange(LPXLOPER pxRefText, LPXLOPER pxDlg, WORD wDlgRow)
{
LPXLOPER px;
// put into dialog box
px = (LPXLOPER)(&pxDlg->val.array.lparray[wDlgRow*7+6]);
px->xltype=xltypeStr;
px->val.str=pxRefText->val.str;
return 1;
}
////////////////////////////////////////////////////////////////////////
//
// Global reference creation functions
// The global reference gxOutRef and gxInRef are used for
// communication with the worksheet. The following routines are
// used to create these global refences either from single
// references or general references. Generally, you will
// create a global reference and then define the size of the range
// with RefSetRectangle().
//
///////////////////////////////////////////////////////////////////////
//
// CreateGlobalRef() - create a global refence. pgxRef is a global
// reference: gxOutRef or gxInRef. The global reference
// is created either from a single reference (xltypeSref) or
// a general reference (xltypeRef). The global references are
// limited to a single continuous range.
//
BOOL PASCAL CreateGlobalRef(LPXLOPER pgxRef, LPXLOPER pxDialog, WORD wDlgRow)
{
XLOPER xTemp;
// get range from dialog & change to reference
Excel(xlfTextref, &xTemp, 2,
(LPXLOPER)&pxDialog->val.array.lparray[wDlgRow*7+6],
TempBool(FALSE));
// abort discontinuous regions or bad ref
if (!RefIsContinuous(&xTemp))
{
// abort multi region refs
ErrorHandler(XLU_BAD_REF);
Excel(xlFree, 0, 1, (LPXLOPER)&xTemp);
return FALSE;
}
// create global REF
if (xTemp.xltype == xltypeSRef)
{
// SRef type reference, change to Ref
InitGlobalRefFromSRef(pgxRef, &xTemp);
}
else if (xTemp.xltype == xltypeRef)
{
// Ref type ref
InitGlobalRefFromRef(pgxRef, (LPXLOPER)&xTemp);
}
return TRUE;
}
//
// RefIsContinuous() - returns true if SRef or continuous
//
BOOL PASCAL RefIsContinuous(LPXLOPER pxRef)
{
LPXLMREF lpxlm;
if (pxRef->xltype == xltypeSRef)
// SRef always continuous
return TRUE;
if (pxRef->xltype == xltypeRef)
{
// check count of Ref
lpxlm = pxRef->val.mref.lpmref;
// ok if unity
if (lpxlm->count == 1)
return TRUE;
else
return FALSE;
}
// not a ref
return FALSE;
}
//
// IsReferencesOverlapped() - check overlapping ranges
//
BOOL IsReferencesOverlapped(LPXLOPER pxRef1, LPXLOPER pxRef2)
{
LPXLMREF lpxlm1, lpxlm2;
// not reference types
if (pxRef1->xltype != xltypeRef || pxRef2->xltype != xltypeRef)
return FALSE;
// different id's not overlapped
if (pxRef1->val.mref.idSheet != pxRef2->val.mref.idSheet)
return FALSE;
// single ref only
lpxlm1 = pxRef1->val.mref.lpmref;
lpxlm2 = pxRef2->val.mref.lpmref;
// not if
if ((lpxlm1->reftbl[0].rwFirst > lpxlm2->reftbl[0].rwLast) || // below
(lpxlm1->reftbl[0].rwLast < lpxlm2->reftbl[0].rwFirst) || // above
(lpxlm1->reftbl[0].colFirst > lpxlm2->reftbl[0].colLast) || // to right
(lpxlm1->reftbl[0].colLast < lpxlm2->reftbl[0].colFirst)) // to left
return FALSE;
ErrorHandler(XLU_OVERLAPPED_REF);
return TRUE;
}
//
// InitGlobalRefFromSref()
//
void InitGlobalRefFromSRef(LPXLOPER pgxRef, LPXLOPER pxSRef)
{
LPXLMREF lpmRef;
// get pointer to xlmref from global ref
lpmRef = pgxRef->val.mref.lpmref;
// set xltype
pgxRef->xltype = xltypeRef;
// set SheetId
pgxRef->val.mref.idSheet = gxActiveSheetId.val.mref.idSheet;
// set count
lpmRef->count = 1;
// set rows
lpmRef->reftbl[0].rwFirst = pxSRef->val.sref.ref.rwFirst;
lpmRef->reftbl[0].rwLast = pxSRef->val.sref.ref.rwLast;
// set cols
lpmRef->reftbl[0].colFirst = pxSRef->val.sref.ref.colFirst;
lpmRef->reftbl[0].colLast = pxSRef->val.sref.ref.colLast;
}
//
// InitGloablRefFromRef()
//
void InitGlobalRefFromRef(LPXLOPER pgxRef, LPXLOPER pxRef)
{
LPXLMREF lpgmRef, lpmRef;
// get pointer to global mref
lpgmRef = pgxRef->val.mref.lpmref;
// get pointer to source reference mref
lpmRef = pxRef->val.mref.lpmref;
// set xltype
pgxRef->xltype = xltypeRef;
// set SheetId
pgxRef->val.mref.idSheet = pxRef->val.mref.idSheet;
// set count
lpgmRef->count = 1;
// set rows
lpgmRef->reftbl[0].rwFirst = lpmRef->reftbl[0].rwFirst;
lpgmRef->reftbl[0].rwLast = lpmRef->reftbl[0].rwLast;
// set cols
lpgmRef->reftbl[0].colFirst = lpmRef->reftbl[0].colFirst;
lpgmRef->reftbl[0].colLast = lpmRef->reftbl[0].colLast;
}
////////////////////////////////////////////////////////////////////////
//
// general reference helper functions
//
///////////////////////////////////////////////////////////////////////
//
// IncxlmRefRow() - increments the row to point to one row
// below the row as defined in input. The range rectangle is
// not changed. This is used to write successive blocks one
// below the next.
void IncxlmRefRow(LPXLOPER pxRef)
{
LPXLMREF pxlmRef;
WORD wRows;
// make the reference point to the row below the last
// never change the rectangle
pxlmRef = pxRef->val.mref.lpmref;
wRows = pxlmRef->reftbl[0].rwLast - pxlmRef->reftbl[0].rwFirst + 1;
pxlmRef->reftbl[0].rwFirst = pxlmRef->reftbl[0].rwLast+1;
pxlmRef->reftbl[0].rwLast += wRows;
}
//
// IncxlmRefCol() - increment column (see InxlmRefRow() above
//
void IncxlmRefCol(LPXLOPER pxRef)
{
LPXLMREF pxlmRef;
BYTE nCols;
// increment first col 1 greater than last
pxlmRef = pxRef->val.mref.lpmref;
nCols = pxlmRef->reftbl[0].colLast - pxlmRef->reftbl[0].colFirst + 1;
pxlmRef->reftbl[0].colFirst = pxlmRef->reftbl[0].colLast+1;
pxlmRef->reftbl[0].colLast += nCols;
}
//
// RefSetRectangle() - create a rectangular reference from a previously
// initialized reference.
//
void RefSetRectangle(LPXLOPER pxRef, WORD wRows, BYTE nCols)
{
LPXLMREF pxlmRef;
// make the reference a rectangle based on first
pxlmRef = pxRef->val.mref.lpmref;
pxlmRef->reftbl[0].rwLast = pxlmRef->reftbl[0].rwFirst + wRows -1;
pxlmRef->reftbl[0].colLast = pxlmRef->reftbl[0].colFirst + nCols -1;
}